
import time
import os 
import sys
import numpy as np

from pynput.keyboard import Listener as kLis
from pynput.keyboard import Key as kKey
from pynput.keyboard import Controller as kCtl
from pynput.mouse import Button as mBut
from pynput.mouse import Controller as mCtl
import random

# 游戏界面定义
shape = [15, 10]
data = np.zeros((shape[0]+2, shape[1]+2), dtype=int, order='C')
data[:, 0] = 2 # 左
data[:, data.shape[1] - 1] = 2 # 右
data[0] = 3 # 上
data[data.shape[0] - 1] = 4  # 下

# 方块
shape01 = [
    [
        [
            [0, 0, 0],
            [1, 0, 0],
            [1, 1, 1]
        ], [
            [1, 1, 0],
            [1, 0, 0],
            [1, 0, 0]
        ], [
            [0, 0, 0],
            [1, 1, 1],
            [0, 0, 1]
        ], [
            [0, 0, 1],
            [0, 0, 1],
            [0, 1, 1]
        ],
    ],
    [
        [
            [0, 0, 0],
            [0, 0, 1],
            [1, 1, 1]
        ], [
            [1, 0, 0],
            [1, 0, 0],
            [1, 1, 0]
        ], [
            [0, 0, 0],
            [1, 1, 1],
            [1, 0, 0]
        ], [
            [0, 1, 1],
            [0, 0, 1],
            [0, 0, 1]
        ],
    ], [
        [
            [0, 0, 0],
            [0, 1, 0],
            [1, 1, 1]
        ], [
            [0, 1, 0],
            [0, 1, 1],
            [0, 1, 0]
        ], [
            [0, 0, 0],
            [1, 1, 1],
            [0, 1, 0]
        ], [
            [0, 1, 0],
            [1, 1, 1],
            [0, 0, 0]
        ],
    ], [
        [
            [0, 1, 0],
            [0, 1, 0],
            [0, 1, 0]
        ], [
            [0, 0, 0],
            [1, 1, 1],
            [0, 0, 0]
        ], [
            [0, 1, 0],
            [0, 1, 0],
            [0, 1, 0]
        ], [
            [0, 0, 0],
            [1, 1, 1],
            [0, 0, 0]
        ],
    ], [
        [
            [1, 0],
            [1, 1]
        ], [
            [1, 1],
            [1, 0]
        ], [
            [1, 1],
            [0, 1]
        ], [
            [0, 1],
            [1, 1]
        ],
    ], [
        [[1]],
        [[1]],
        [[1]],
        [[1]]
    ]
]

shape01_len = 24

shape_id = 24 -1 

b_h = '^------------------^'
b_b = '|                  |'
b_f = 'v------------------v'
ds = data.shape

# 游戏主界面， [当前形状编码， 形状位置]， 下一个形状编码， 分数
def print_game(data, es, dn, score):
    sc_x = 2
    sc_y = int(ds[0] * 0.2)
    dn_x = 2
    dn_y = int(ds[0] * 0.5)

    # ------------- 分数显示 -------------
    bl = len(b_b)
    sc_l = 'score: '+str(score)
    sc_l = '| ' + sc_l + ' ' * (bl - len(sc_l) - 4) + ' |'
    # ------------- ------------- -------------
    
    # ------------- 下一个形状 -------------
    dn_l = 'next:'
    dn_l = '| ' + dn_l + ' ' * (bl - len(dn_l) - 4) + ' |'
    dn_s = []
    for i in shape01[dn // 4][dn % 4]:
        s = '|      ' 
        for j in i:
            if j == 0:
                s += '  '
            elif j == 1:
                s += 'x '
        s += ' ' * (bl - len(s) - 3) + '  |'
        dn_s.append(s)
    # ------------- ------------- -------------

    # ------------- 移动图像位置 -------------
    tes = []
    for ei, i in enumerate(shape01[es[0] // 4][es[0] % 4]):
        if ei + es[1] < 0:
            ts = '  '
        else:
            ts = '0 '
            pass
        s = ts * es[2]
        for j in i:
            if j == 0:
                s += ts
            elif j == 1:
                s += 'x '
        s += ts * (ds[1] - len(s)//2)
        tes.append(s)
    # ------------- ------------- -------------

    # ------------- 游戏界面 -------------
    for ei, i in enumerate(data):
        # ------- 显示界面 -------
        print('%2s' % ei,end=' ')
        gd = []
        for j in i:
            if j == 0: gd.append( '  ')
            elif j == 1: gd.append('x ')
            elif j == 2: gd.append('| ')
            elif j == 3: gd.append('  ')
            elif j == 4: gd.append('--')
        if ei >= es[1] - 2 and ei < es[1] + len(shape01[es[0] // 4][es[0] % 4]) - 2:
            for em, m in enumerate(shape01[es[0] // 4][es[0] % 4][ei + 2-es[1]]):
                if m == 1 and (es[2]+em)-1 < len(gd):
                    gd[(es[2]+em)-1] = 'x '
        print(''.join(gd), end='')
        
        # ------ 状态界面 -------
        if ei == 0:
            print(b_h,end='')
        elif ei == ds[0]-1:
            print(b_f, end='')
        elif ei == sc_y:
            print(sc_l, end='')
        elif ei == dn_y:
            print(dn_l, end='')
        elif ei > dn_y + 1 and ei < dn_y + len(dn_s) + 2:
            print(dn_s[ei-dn_y-2], end='')
        else:
            print(b_b, end='')
        print()
    # ------------- ------------- -------------



def is_stand (data, es):
    for ei,i in enumerate(shape01[es[0]//4][es[0] % 4]):
        for ej, j in enumerate(i):
            dt = data[es[1]+ei-1, es[2]+ej-1]
            if j == 1 and (dt == 1 or dt == 4):
                return True
    return False


def is_over(data, es):
    for ei, i in enumerate(shape01[es[0]//4][es[0] % 4]):
        for ej, j in enumerate(i):
            dt = data[es[1] + ei - 2, es[2] + ej - 2]
            if j == 1 and dt == 3:
                return True
    return False

score = 0

def do_clean(data):
    global score
    line_count = []
    line = np.ones([shape[1]], dtype=int)
    for ea, a in enumerate(data[1:-1]):
        if np.equal(a[1:-1], line).all():
            line_count.append(ea)
    for li in line_count:
        data[2: li + 2, 1:-1] = data[1: li + 1, 1:-1]
    data[1][1:-1] = np.zeros([shape[1]], dtype=int)
    score += len(line_count)

def can_change(data, es):
    for ei, i in enumerate(shape01[es[0]//4][es[0] % 4]):
        for ej, j in enumerate(i):
            dt = data[es[1] + ei - 2, es[2] + ej - 2]
            if j == 1 and (dt in [1,2,4]):
                return False
    return True


# ------  游戏状态的全局变量 -------
nx_sh_id = random.randrange(0, shape01_len) # 下一个方块的id值，用随机数产生
ps_y = 0 # 方块位置x坐标
ps_x = 0  # 方块位置y坐标
sh_id =0  # 记录当前方块的编号
stime = 1 # 每一步的等待时间
# ------------- -----------------

def press(key):
    global ps_x
    global ps_y
    global sh_id
    global nx_sh_id
    global stime
    
    if str(key).strip('\'') == 'a':
        if can_change(data, [sh_id, ps_y, ps_x]):
            ps_x -= 1
    elif str(key).strip('\'') == 'd':
        if can_change(data, [sh_id, ps_y, ps_x+2]):
            ps_x += 1
    elif str(key).strip('\'') == 'w':
        t1 = sh_id % 4
        t2 = sh_id // 4
        t3 = t2*4 + (t1+1)%4
        if can_change(data, [t3, ps_y, ps_x+1]):
            sh_id = t3
    elif str(key).strip('\'') == 's':
        # ps_y = 
        stime = 0.2

    print('\033[2K\033[1A \033[1C')
    print("\033[2J")
    print_game(data, [sh_id, ps_y, ps_x], nx_sh_id, score)
    sys.stdout.flush()


listener = kLis(on_press=press) 
listener.start()

while True:
    sh_id = nx_sh_id
    nx_sh_id = random.randrange(0, shape01_len)
    ps_y = 0
    ps_x = ds[1]//2-len(shape01[sh_id//4][sh_id % 4][0])//2
    stime = 1
    while True:
        ps_y += 1
        print("\033[2J")
        print_game(data, [sh_id, ps_y, ps_x], nx_sh_id, score)
        time.sleep(stime)
        
        # 判断是否结束下坠
        df = is_stand(data, [sh_id, ps_y, ps_x])
        if df:
            print('done')
            break
    s_w = len(shape01[sh_id // 4][sh_id % 4][0])
    s_h = len(shape01[sh_id // 4][sh_id % 4])
    # 判断是否完结
    if is_over(data, [sh_id, ps_y, ps_x]):
        print('game over')
        break
        
    data[ps_y-2:ps_y+s_h-2, ps_x-1:ps_x +
         s_w-1] += np.array(shape01[sh_id // 4][sh_id % 4], dtype=int)
    # 判断是否消行
    do_clean(data)

listener.join()
